﻿using System.Collections.Generic;
using TrueSync;
using TrueSync.Physics2D;
using Network;

public enum AttachToParentSyncMethodEnum
{
    SyncPosition,
    SyncRotation,
    SyncBothPositionAndRotation
}
[System.Serializable]
public class HangpointAnimationTrace
{
    public string Name;
    public HangpointTrace HangpointTrace;
    public void Deserialize(EByte ms)
    {
        Name = ms.ReadString();
        HangpointTrace = new HangpointTrace();
        HangpointTrace.Deserialize(ms);
    }

    public void Serialize(EByte ms)
    {
        ms.WriteString(Name);
        HangpointTrace.Serialize(ms);
    }
}

[System.Serializable]
public class AnimationInfo
{
    public string AnimationName;
    public int TotalFramesNum;
    public bool IsLoop;
    public Dictionary<string, HangpointTrace> HangpointAnimationTrace;
    public List<HangpointAnimationTrace> HangpointAnimationTraceList;

    public Dictionary<string, HangpointSpaceInfo> Sample(int frame, TSVector2 worldPosition)
    {
        Dictionary<string, HangpointSpaceInfo> ret = new Dictionary<string, HangpointSpaceInfo> ();
        foreach(var item in HangpointAnimationTrace)
        {
            HangpointSpaceInfo spaceInfo = item.Value.Sample(frame);
            spaceInfo.Position += worldPosition;
            ret[item.Key] = spaceInfo;
        }
        return ret;
    }

    public void Deserialize(EByte ms)
    {
        AnimationName = ms.ReadString();
        TotalFramesNum = ms.ReadInt();
        IsLoop = ms.ReadInt() == 1;
        HangpointAnimationTrace = new Dictionary<string, HangpointTrace>();
        int HangpointAnimationTraceListNum = ms.ReadInt();
        HangpointAnimationTraceList = new List<HangpointAnimationTrace>(HangpointAnimationTraceListNum);
        for (int i = 0; i < HangpointAnimationTraceListNum; i++)
        {
            HangpointAnimationTraceList.Add(new HangpointAnimationTrace());
            HangpointAnimationTraceList[i].Deserialize(ms);
            HangpointAnimationTrace.Add(HangpointAnimationTraceList[i].Name, HangpointAnimationTraceList[i].HangpointTrace);
        }
    }

    public void Serialize(EByte ms)
    {
        ms.WriteString(AnimationName);
        ms.WriteInt(TotalFramesNum);
        ms.WriteInt(IsLoop ? 1 : 0);
        ms.WriteInt(HangpointAnimationTraceList.Count);
        for (int i = 0; i < HangpointAnimationTraceList.Count; i++)
        {
            HangpointAnimationTraceList[i].Serialize(ms);
        }

    }
}
[System.Serializable]
public class HangpointTrace
{
    public List<HangpointSpaceInfo> TraceFrames;

    public HangpointSpaceInfo Sample(int frame)
    {
        if (frame < 0) frame = 0;
        if (frame > TraceFrames.Count) frame = TraceFrames.Count;
        return TraceFrames[frame];
    }

    public void Serialize(EByte ms)
    {
        ms.WriteInt(TraceFrames.Count);
        for (int i = 0; i < TraceFrames.Count; i++)
        {
            TraceFrames[i].Serialize(ms);
        }
    }

    public void Deserialize(EByte ms)
    {
        int TotalFramesNum = ms.ReadInt();
        TraceFrames = new List<HangpointSpaceInfo>(TotalFramesNum);
        for (int i = 0; i < TotalFramesNum; i++)
        {
            TraceFrames.Add(new HangpointSpaceInfo());
            TraceFrames[i].Deserialize(ms);
        }
    }
}
[System.Serializable]
public struct HangpointSpaceInfo
{
    public TSVector2 Position;
    public FP Rotation;

    public void Serialize(EByte ms)
    {
        ms.WriteLong(Position.x.RawValue);
        ms.WriteLong(Position.y.RawValue);
        ms.WriteLong(Rotation.RawValue);
    }

    public void Deserialize(EByte ms)
    {
        Position = new TSVector2(FP.FromRaw(ms.ReadLong()), FP.FromRaw(ms.ReadLong()));
        Rotation = FP.FromRaw(ms.ReadLong());
    }
}

public class AttachedFixture
{
    public string HangpointName;
    public AttachToParentSyncMethodEnum SyncMethod;
    public Fixture Rect;
}

public class LogicAnimationComponent : LogicComponent
{
    LogicEntity mLEntity;
    LogicMoveComponent mMoveComponent;
    Dictionary<string, AnimationInfo> mAnimationInfos;
    AnimationInfo mCurrentAnimationInfo;
    int mFrames;
    public Dictionary<string, HangpointSpaceInfo> CurrentFrameHangpointSpaceInfo
    { private set; get; }
    List<AttachedFixture> mAttachedRects;

    public void Init(LogicEntity LEntity)
    {
        mLEntity = LEntity;
        mAttachedRects = new List<AttachedFixture>();
        mAnimationInfos = new Dictionary<string, AnimationInfo>();


    }

    public void Start()
    {
        mFrames = 0;
        mMoveComponent = mLEntity.GetLogicComponent<LogicMoveComponent>();
    }

    public void DoUpdate(FP deltaTime)
    {
        if (mCurrentAnimationInfo == null)
            return;

        mFrames++;
        CurrentFrameHangpointSpaceInfo = mCurrentAnimationInfo.Sample(mFrames, mMoveComponent.Position);
        mLEntity.SendEntityMessage((int)L2VMsgId.StepAnimation);

        for(int i = 0; i <mAttachedRects.Count; i++)
        {
            if (mAttachedRects[i].Rect.Enabled == false)
                continue;
            string hangpoint = mAttachedRects[i].HangpointName;
            if (CurrentFrameHangpointSpaceInfo.ContainsKey(hangpoint) == false)
            {
                mAttachedRects[i].Rect.Update(new TSTransform(mMoveComponent.Position, new Rot(0), mMoveComponent.FaceDirection == 1));
            }
            else
            {
                HangpointSpaceInfo info = CurrentFrameHangpointSpaceInfo[hangpoint];
                switch (mAttachedRects[i].SyncMethod)
                {
                    case AttachToParentSyncMethodEnum.SyncPosition:
                        mAttachedRects[i].Rect.Update(new TSTransform(info.Position, new Rot(0), mMoveComponent.FaceDirection == 1));
                        break;
                    case AttachToParentSyncMethodEnum.SyncRotation:
                        mAttachedRects[i].Rect.Update(new TSTransform(TSVector2.zero, new Rot(info.Rotation), mMoveComponent.FaceDirection == 1));
                        break;
                    case AttachToParentSyncMethodEnum.SyncBothPositionAndRotation:
                        mAttachedRects[i].Rect.Update(new TSTransform(info.Position, new Rot(info.Rotation), mMoveComponent.FaceDirection == 1));
                        break;
                }
            }
        }

        if(mFrames == mCurrentAnimationInfo.TotalFramesNum - 1)
        {
            if (mCurrentAnimationInfo.IsLoop)
            {
                mFrames = 0;
            }
            else
            {
                mLEntity.GetLogicComponent<LogicStateMachineComponent>().CurrentState.OnCurrentAnimationFinished();
            }
        }
    }

    public void Destroy()
    {
    }

    void LoadAnimation(string AnimationName)
    {
        if (mAnimationInfos.ContainsKey(AnimationName))//已经有了动画信息不要再从磁盘读取了
            return;
        EByte info = LFileLoader.ReadFile("Txt/" + mLEntity.characterID + "/" + AnimationName);
        AnimationInfo animationInfo = new AnimationInfo();
        animationInfo.Deserialize(info);
        mAnimationInfos[animationInfo.AnimationName] = animationInfo;
    }
   
    public void ChangeToAnimation(string AnimationName)
    {
        mFrames = 0;
        if (AnimationName == null)
        {
            mCurrentAnimationInfo = null;
            return;
        }

        mLEntity.SendEntityMessage((int)L2VMsgId.PlayAnimation, AnimationName);

        LoadAnimation(AnimationName);
        mCurrentAnimationInfo = mAnimationInfos.ContainsKey(AnimationName) ? mAnimationInfos[AnimationName] : null;
        if (mCurrentAnimationInfo == null)
            return;
        CurrentFrameHangpointSpaceInfo = mCurrentAnimationInfo.Sample(mFrames, mMoveComponent.Position);
    }

    public void AddToHangpoint(string hangpointName, Fixture fixture, AttachToParentSyncMethodEnum syncMethod)
    {
        //一个框提已经被加到其他的挂点上了
        if (mAttachedRects.Find((attachedRect) => attachedRect.Rect == fixture) != null)
            return;

        mAttachedRects.Add(new AttachedFixture
        {
            Rect = fixture,
            HangpointName = hangpointName,
            SyncMethod = syncMethod
        });
    }

    public void RemoveFromHangpoint(Fixture fixture)
    {
        mAttachedRects.RemoveAll((attachedRect) => attachedRect.Rect == fixture);
    }
}
